#include "file_impl.h"

/////////////////////////////////////////////////////////////////////////////////////////
// 
namespace xos
{
    file_impl::file_impl()
    {
        memset( m_szFileName, 0, sizeof( m_szFileName ) );
        m_hFile = INVALID_HANDLE_VALUE;
        m_enumType = FILE_TYPE_NONE;
    }

    file_impl::~file_impl()
    {
        term();
    }

    ////////////////////////////////////////////////////////////////////////////////////
    // 

    int file_impl::init()
    {
        int nRet = 0;
        return nRet;
    }

    int file_impl::term()
    {
        int nRet = 0;

        if( INVALID_HANDLE_VALUE != m_hFile )
        {
            CloseHandle( m_hFile );
            m_hFile = INVALID_HANDLE_VALUE;
        }

        m_enumType = FILE_TYPE_NONE;

        return nRet;
    }

    ////////////////////////////////////////////////////////////////////////////////////
    // 

    // 
    // get file or dir name
    // 
    const char * file_impl::get_name( char * lpszFileName, int nLen, int * pnLenNeeded )
    {
        int len = ( int )strlen( m_szFileName );

        if( pnLenNeeded )
        {
            *pnLenNeeded = len;
        }

        if( lpszFileName && ( nLen > len ) )
        {
            strcpy_s( lpszFileName, nLen, m_szFileName );
        }

        return m_szFileName;
    }

    // 
    // is file or dir ? 
    // 
    i_file::enumFileType file_impl::get_type()
    {
        return m_enumType;
    }

    //////////////////////////////////////////////////////////////////////////////////
    // 
    // open a file
    // 
    int file_impl::open( const char * lpszFileName, unsigned long ulAccessFlag, unsigned long ulShareMode, unsigned long ulCreateFlag )
    {
        int nRet = 0;

        unsigned long ulFileAccess = 0, ulFileOpen = 0, ulShare = 0;

        // access type

        if( FILE_WRITE & ulAccessFlag )
        {
            ulFileAccess |= GENERIC_WRITE;
            ulFileAccess |= GENERIC_READ;
        }

        if( FILE_READ & ulAccessFlag )
        {
            ulFileAccess |= GENERIC_READ;
        }

        // create type

        if( ulCreateFlag & FILE_CREATE )
        {
            ulFileOpen |= OPEN_ALWAYS;
        }

        if( ulCreateFlag & FILE_OPEN )
        {
            ulFileOpen |= OPEN_EXISTING;
        }

        // 
        // share type
        // 
        if( ulShareMode & SHARE_READ )
        {
            ulShare |= FILE_SHARE_READ;
        }

        if( ulShareMode & SHARE_WRITE )
        {
            ulShare |= FILE_SHARE_WRITE;
        }

        // 
        // use unicode in windows
        // 
        {
            WCHAR name[4096] = { 0 };

            misc_tool::utf8_to_wchar( lpszFileName, -1, name, sizeof( name ), 0 );

            m_hFile = CreateFileW( 
                name, 
                ulFileAccess,
                ulShare,
                0,
                ulFileOpen,
                FILE_ATTRIBUTE_NORMAL,
                0 );
        }

        if( INVALID_HANDLE_VALUE == m_hFile )
        {
            nRet = 1;
        }

        if( 0 == nRet )
        {
            m_enumType = FILE_TYPE_FILE;
        }

        return nRet;
    }

    // 
    // write file data
    // 
    // -1 means failed. other , write bytes
    // 
    int file_impl::write( const void * lpBuf, unsigned long ulBufSize )
    {
        int nRet = 0;

        if( INVALID_HANDLE_VALUE == m_hFile )
        {
            nRet = -1;
        }

        if( 0 == nRet )
        {
            DWORD dwLen = 0;

            if( WriteFile( m_hFile, lpBuf, ulBufSize, &dwLen, 0 ) )
            {
                nRet = dwLen;
            }
            else
            {
                nRet = -1;
            }
        }

        return nRet;
    }

    // 
    // read file data
    // 
    // -1 means failed. other , read bytes
    //
    int file_impl::read( void * lpBuf, unsigned long ulBufSize )
    {
        int nRet = 0;

        if( INVALID_HANDLE_VALUE == m_hFile )
        {
            nRet = -1;
        }

        if( 0 == nRet )
        {
            DWORD dwLen = 0;

            if( ReadFile( m_hFile, lpBuf, ulBufSize, &dwLen, 0 ) )
            {
                nRet = dwLen;
            }
            else
            {
                nRet = -1;
            }
        }

        return nRet;
    }

    // 
    // close file handle
    //  
    int file_impl::close()
    {
        int nRet = 0;

        memset( m_szFileName, 0, sizeof( m_szFileName ) );
        m_enumType = FILE_TYPE_NONE;

        if( INVALID_HANDLE_VALUE != m_hFile )
        {
            CloseHandle( m_hFile );
            m_hFile = INVALID_HANDLE_VALUE;
        }

        return nRet;
    }

    // 
    // move file pointer to ...
    // 
    int file_impl::set_file_pos( enumFilePos enumFrom, xos_i64 iPos64 )
    {
        int nRet = 0;

        LARGE_INTEGER llToMove = { 0 }, llPos = { 0 };
        DWORD dwType = 0;

        if( 0 == nRet )
        {
            switch( enumFrom )
            {
            case FILE_POS_BEGIN:
                {
                    dwType = FILE_BEGIN;
                }
                break;
            case FILE_POS_CUR:
                {
                    dwType = FILE_CURRENT;
                }
                break;
            case FILE_POS_END:
                {
                    dwType = FILE_END;
                }
                break;
            default:
                {
                    nRet = 1;
                }
                break;
            }
        }

        if( 0 == nRet )
        {
            if( INVALID_HANDLE_VALUE == m_hFile )
            {
                nRet = 1;
            }
        }

        if( 0 == nRet )
        {
            llToMove.QuadPart = iPos64;

            if( !SetFilePointerEx( m_hFile, llToMove, &llPos, dwType ) )
            {
                nRet = 1;
            }
        }

        return nRet;
    }

    // 
    // get current file pointer
    // 
    int file_impl::get_file_pos( xos_i64 * lpSize64 )
    {
        int nRet = 0;

        LARGE_INTEGER llToMove = { 0 }, llPos = { 0 };

        if( INVALID_HANDLE_VALUE == m_hFile )
        {
            nRet = 1;
        }

        if( lpSize64 )
        {
            *lpSize64 = 0;
        }

        if( 0 == nRet )
        {
            if( !SetFilePointerEx( m_hFile, llToMove, &llPos, FILE_BEGIN ) )
            {
                nRet = 1;
            }
        }

        if( 0 == nRet )
        {
            if( lpSize64 )
            {
                *lpSize64 = llPos.QuadPart;
            }
        }

        return nRet;
    }

    // 
    // get file size
    // 
    int file_impl::get_file_size( xos_i64 * lpSize64 )
    {
        int nRet = 0;

        LARGE_INTEGER llSize = { 0 };

        if( INVALID_HANDLE_VALUE == m_hFile )
        {
            nRet = 1;
        }

        if( lpSize64 )
        {
            *lpSize64 = 0L;
        }

        if( 0 == nRet )
        {
            if( !GetFileSizeEx( m_hFile, &llSize ) )
            {
                nRet = 1;
            }
        }

        if( 0 == nRet )
        {
            if( lpSize64 )
            {
                *lpSize64 = llSize.QuadPart;
            }
        }

        return nRet;
    }

    // 
    // commit file disk space.
    // 
    int file_impl::commit_file( xos_i64 iPos64 )
    {
        int nRet = 0;

        LARGE_INTEGER ulSize;
        void * pView = 0;
        HANDLE hMap = 0;

        ulSize.QuadPart = ( LONGLONG )iPos64;

        if( 0 == nRet )
        {
            hMap = CreateFileMapping( m_hFile, 0, PAGE_READWRITE, ulSize.HighPart, ulSize.LowPart, 0 );

            if( !hMap )
            {
                nRet = 1;
            }
        }

        if( 0 == nRet )
        {
            pView = MapViewOfFile( hMap, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0 );
        }

        if( pView )
        {
            UnmapViewOfFile( pView );
            pView = 0;
        }

        if( hMap )
        {
            CloseHandle( hMap );
            hMap = 0;
        }

        return nRet;
    }

    // 
    // release
    // 
    int file_impl::release()
    {
        int nRet = 0;

        term();
        put_back_lock();

        return nRet;
    }
} // xos
